/**
 * @version	0.6.3
 *    Change Log:
 *      - 0.6.0: Original Version : Jung-Jae Kim
 *      - 0.6.1: Added BlackBerry Database connector : Bart
 *      - 0.6.2: Removed unnecessary lines : JJ Kim
 *      - 0.6.3: Map class modified : JJ Kim
 **/
/********************************************************************************************
 * XML Handler																				*
 ********************************************************************************************/

/**
 * XML을 정해진 규격에 따라 Parsing하는 클래스.
 * 각 프로젝트에서는 이 클래스를 확장하여 해당 프로젝트의 XML 규격에 맞는 parse와 make를 구현하여 해당 프로젝트에서 xml 관련 처리를 일원화 할 수 있다.
 * @constructor
 */
function XmlHandler() {
}

/**
 * XML을 parsing하여 규격화된 Data양식인 DataSet으로 변환합니다.
 * @param xmlStr 변환할 xml String
 */
XmlHandler.prototype.parse = function(xmlStr) {
	var xml = (new DOMParser()).parseFromString(xmlStr, "text/xml");
	var dataset = new DataSet();
	var list = new Array();
	
	x = xml.getElementsByTagName("item");
	
	for(var i = 0; i<x.length; i++) {
		var map = new Map();
		y = x[i].childNodes;
		
		for (var j = 0; j < y.length; j++) {
			if(y[j].nodeName.substring(0, 1) != "#") {
				if(y[j].childNodes[0])
					map.put(y[j].nodeName, y[j].childNodes[0].nodeValue);
			}
		}
		list.push(map);
		
	}
	dataset.putList("list",list);
	
	if(xml.getElementsByTagName("data") == null || xml.getElementsByTagName("data").length == 0) 
		return dataset;
		
	x = xml.getElementsByTagName("data")[0].childNodes;
	for (i=0;i<x.length;i++) {
		
		if(x[i].nodeName.substring(0, 1) != "#") {
			if(x[i].childNodes[0])
				dataset.put(x[i].nodeName, x[i].childNodes[0].nodeValue);
		}
	}
	
	return dataset;
};

/**
 * 정해진 규약에 따라 서버로 전송할 XML을 생성합니다.
 * @param params 전송할 parameter 목록
 */
XmlHandler.prototype.make = function(params) {
};

/**
 * 데이터 요청과 xml변환이 합쳐진 method로서 params를 사용하여 xml 요청문을 만든 다음 지정된 url로 데이터를 요청한다.
 * @param url xml을 전송할 서버의 주소
 * @param params 전송할 parameter 목록
 */
XmlHandler.prototype.send = function(url, params) {
};

function SKTXmlHandler() {
	this.base = XmlHandler;
	this.base();
	
//	this.defaultParams = new Object();
//	this.defaultParams["primitive"] = "BULLETIN_NOTICE";
//	this.defaultParams["function"] = "BULLETIN_LIST";
//	this.defaultParams["authKey"] = "c068e13c3f04ddf1acaa020f88504edd767bc3c0";
//	this.defaultParams["mdn"] = "01033392731";
//	this.defaultParams["appId"] = "PW00000001";
//	this.defaultParams["appVer"] = "1.0.0";
//	this.defaultParams["page"] = "1";
}

SKTXmlHandler.prototype=new XmlHandler;

SKTXmlHandler.prototype.parse = function(xmlStr) {
	var xml = (new DOMParser()).parseFromString(xmlStr.replace(/^\s+/g,'').replace(/\s+$/g,''), "text/xml");
	var dataset = new DataSet();

	lists = xml.getElementsByTagName("list");
//	log.log("SKTXmlHandler.parse: number of list = " + lists.length);
	
	for(var k = 0; k < lists.length; k++) {
		var list = new Array();
		
		listNameNode = lists[k].getElementsByTagName("listName");
		key = "";
		if(listNameNode != null && listNameNode.length != 0) {
			key = listNameNode[0].childNodes[0].nodeValue;
			key = key.replace(/^\s+/g,'').replace(/\s+$/g,'');	
		}

		x = lists[k].getElementsByTagName("item");
		for (var i=0;i<x.length;i++) {
			var map = new Map();
			y = x[i].childNodes;
			for (var j=0;j<y.length;j++) {
				
				if(y[j].nodeName.substring(0, 1) != "#") {
					if(y[j].childNodes[0])
						map.put(y[j].nodeName, y[j].childNodes[0].nodeValue);
				}
			}
			
			list.push(map);
		}
		dataset.putList(key, list);
//		log.log("SKTXmlHandler.parse: key=" + key + ", value=" + list + "(" + list.length + ")");
	}
	
	if(xml.getElementsByTagName("data") == null || xml.getElementsByTagName("data").length == 0) 
		return dataset;
	
	x = xml.getElementsByTagName("data")[0].childNodes;
	
	for (i=0;i<x.length;i++) {
		if(x[i].nodeName.substring(0, 1) != "#") {
			if(x[i].childNodes[0])
				dataset.put(x[i].nodeName, x[i].childNodes[0].nodeValue);
		}
	}

	return dataset;
};

SKTXmlHandler.prototype.make = function(params) {
	var requestXml = "";
	
//    for (var name in this.defaultParams) {
//        if (typeof(name) != 'string')
//            continue;
//        
//        if(params[name] == "undefined" || params[name] == null) {
//        	params[name] = this.defaultParams[name];
//        }
//    }
	
	
	requestXml += "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"; 
	requestXml += "<Request>";
    if (params != null) {
        for (var name in params) {
            if (typeof(name) != 'string')
                continue;
            
            requestXml += "<" + name + ">" + params[name] + "</" + name + ">";
        }
    }
	requestXml += "</Request>";

	return requestXml;
};

SKTXmlHandler.prototype.send = function(url, params) {
	var requestXml = xmlHandler.make(params);
	http.request(url, "POST", requestXml, onXmlHttpRequest, onXmlErrorHttpRequest);
};

 function onXmlHttpRequest() {
	var xmlStr = http.response;
	
	dataSet = xmlHandler.parse(xmlStr);
	viewLayout.setData(dataSet);
}

function onXmlErrorHttpRequest() {
	log.error("Http Error:" + http.error);
	alert("Http Error:" + http.error);
}





/**********************************************************************************************
 * 					DataSet Class
 **********************************************************************************************/

/**
 * 
 * 데이터를 관리하기 위한 규격화된 데이터양식 클래스. <br>Alopex 내부에서는 이 DataSet을 이용하여 데이터를 관리한다. 
 * 서버에서 받은 XML은 DataSet으로 변환된 후 UI Component에 자동으로 Mapping되어 UI에 표시된다. 
 * 즉 개발자가 추가로 데이터 처리와 UI mapping 작업을 할 필요 없도록  프레임워크에서 데이터처리를 지원한다.
 * @constructor 
 */
function DataSet() {
	/**
	 * 데이터의 항목과 값을 가지고 있는 1차원 map<br>
	 * 예를 들어 제목, 내용, 등록일 항목이 있다면,<br>
	 * map[‘제목’] = ‘제목테스트’<br>
	 * map[‘내용’] = ‘내용테스트’<br>
	 * map[‘등록일’] = ‘2010-12-22’<br>
	 * @members
	 */
	this.map = new Map();
	/**
	 * 리스트를 표현하기 위한 변수
	 * Array의 값들은 map으로서 위의 같이 하나의 1차원 map을 가지고 있다.
	 * @members 
	 */
	this.list = new Map();
}

/**
 * 내용을 가지고 있는 map에 항목 넣기
 * @param key 저장할 키
 * @param value 저장할 값
 */
DataSet.prototype.put = function put(key, value) {
	this.map.put(key, value);
};

/**
 * 내용을 가지고 있는 map에서 값 가져오기
 * @param key 읽어올 값의 키
 */
DataSet.prototype.get = function get(key) {
	return this.map.get(key);
};

/**
 * 리스트를 값 넣기
 * @param key 저장할 키
 * @param value 저장할 값
 */
DataSet.prototype.putList = function putList(key, value) {
	this.list.put(key, value);
};

/**
 * 리스트에서 값
 * @param key 읽어올 값의 키
 */
DataSet.prototype.getList = function getList(key) {
	return this.list.get(key);
};

/**********************************************************************************************
 * 					Map Class
 **********************************************************************************************/

/**
 * Key와 value형태로 값을 관리하기 위한 클래스
 * @constructor
 */
function Map() {
	/**
	 * 목록을 가지고 있는 Array
	 * @members
	 */
	this._array = new Array();
	this._data={};
}

/**
 * 키값으로 index 순서 가져오기
 * @param key index를 알고자 하는 key
 */
Map.prototype._getIndexByKey = function(key) {
	for(var i = 0; i < this._array.length; i++) {
		if(key == this._array[i][0]) {
			return i;
		}
	}
	return -1;
};

/**
 * Index로 key값 가져오기
 * @param index key값을 알고자 하는 index
 * @return 지정된 인덱스에 해당하는 키 값
 */
Map.prototype.getKeyByIndex = function(index) {
	return this._array[index][0];
};

/**
 * Key와 value로 값 설정
 * @param key 저장할 키
 * @param value 저장할 값
 */
Map.prototype.put = function (key, value) {
	this._data[key]=value;
	this._array.push([key,value]);
};

/**
 * Key로 값가져오기
 * @param key 읽어올 값의 키
 * @return 키 값에 매핑된 데이터
 */
Map.prototype.get = function(key) {
	return this._data[key];
};

/**
 * 저장된 항목의 개수를 리턴합니다.
 * @return length 저장된 항목의 수량 
 */
Map.prototype.size = function() {
	return this._array.length;
};

/**
 ****************************************** Database Class **************************************************
 */
var databaseColumns = null;
/**
 * 데이터베이스를 관리하는 클래스.
 * 
 * @constructor
 */
function Database() {
	this.db = null;
	this.dbname = null;
	this.error = null;
}

/**
 * 지정된 데이터 베이스를 엽니다.
 * @param aDBName 데이터베이스 이름
 */
Database.prototype.open = function(aDBName) {
	this.error = null;
	this.dbname = aDBName;
	
	if(device.platformName == "BlackBerry") {
		DatabaseD.open(aDBName);
	} else {
		try {
			if (window.openDatabase) {
				this.db = window.openDatabase(this.dbname, "1.0", this.dbname + "Database", 200000);
				
				if (!this.db)
					this.error = "db error";
			}
			else
				this.error = "db error"; 
		} catch(err) {
			this.db = null;
			this.error = err;
		}
	}
};

/**
 * Query 문을 실행시킵니다.
 * @param sql 실행할 sql query 문
 * @param successCallback sql 실행 성공시 호출되는 콜백함수
 * @param errorCallback sql 실행 실패시 호출되는 콜백함수
 */
Database.prototype.executeQuery = function(sql, successCallback, errorCallback) {
	if (device.platformName == "BlackBerry") {
		DatabaseD.executeQuery(sql, GetFunctionName(successCallback), GetFunctionName(errorCallback));
	} else {
		this.db.transaction(function(tx) {
			tx.executeSql(sql, [], successCallback, errorCallback);
		});
	}
};

/**
 * 데이터의 수정, 삭제 등 데이터를 변경합니다.
 * @param sql 데이터 수정 sql query 문
 * @param arr prepared statement 안에 들어갈 데이터
 */
Database.prototype.executeUpdate = function(sql, arr) {
	if (device.platformName == "BlackBerry") {
		if (arr != null) {
			var s = arr.length;
			var arrStr = "";
			
			for(var i = 0; i < s; i++)
				arrStr += arr[i] + "&";
				
			DatabaseD.executeUpdate(sql, arrStr);
		} else {
			DatabaseD.executeUpdate(sql);	
		}
	} else {
		this.db.transaction(function(tx) {
			if(arr == null)
				tx.executeSql(sql, []);
			else
				tx.executeSql(sql, arr);
				
			this.error = null;
		});
	}
};

/**
 * Query 결과를 파싱합니다.
 * @param results sql 실행 리턴값
 * @param arr
 */
Database.prototype.parse = function(results, arr) {
	var dataset = new DataSet();
//	var rows = results.rows;
	
	var list = new Array();
	for (var i=0;i<results.rows.length;i++) {
		var map = new Map();
		var row = results.rows.item(i);
		for (var j=0;j<arr.length;j++) {
			map.put(arr[j], row[arr[j]]);
			log.log("Database.parse: " + arr[j] + "=" + row[arr[j]]);
		}
		
		list.push(map);
	}
	dataset.putList("select", list);
	
	return dataset;
};

/**
 * 
 */
Database.prototype.send = function(sql, arr) {
	databaseColumns = arr;
	this.executeQuery(sql, this.onDatabaseSuccessHandler, this.onDatabaseErrorHandler);
};

/**
 * Query 문이 성공적으로 실행된 후 호출되는 콜백함수
 * @private
 */
Database.prototype.onDatabaseSuccessHandler = function (transaction, results) {
  dataSet = database.parse(results, databaseColumns);
  viewLayout.setData(dataSet);
//list.setData(dataSet.getList("select"));
};

/**
 * Query 문이 실패한 후 호출되는 콜백함수
 * @private
 */
Database.prototype.onDatabaseErrorHandler = function (error) {
	this.error = error;
	log.log("Database.onDatabaseErrorHandler: " + error);
};
